

#include <stdio.h>
#include <string.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gatt.h>

#include "ble_gatt_discovery.h"

static uint8_t target_addr[6] = {0xC4, 0x17, 0xCD, 0xBF, 0x98, 0xCE};

static struct bt_conn *default_conn;
static struct bt_gatt_exchange_params mtu_exchange_params[CONFIG_BT_MAX_CONN];
// static struct bt_gatt_discover_params discover_params;
// static uint16_t current_service_start_handle;
// static uint16_t current_service_end_handle;

static void scan_result(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf);
static void scan_timeout(void);
static void start_scan(void);

static void conn_connected(struct bt_conn *conn, uint8_t err);
static void conn_disconnected(struct bt_conn *conn, uint8_t reason);
static bool conn_le_param_req(struct bt_conn *conn,
                              struct bt_le_conn_param *param);
static void conn_le_param_updated(struct bt_conn *conn, uint16_t interval,
                                  uint16_t latency, uint16_t timeout);
static void conn_le_phy_updated(struct bt_conn *conn,
                                struct bt_conn_le_phy_info *param);
static void conn_le_data_len_updated(struct bt_conn *conn,
                                     struct bt_conn_le_data_len_info *info);
static void gatt_mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx);

static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
                            struct bt_gatt_exchange_params *params);

static struct bt_gatt_cb gatt_cb = {
    .att_mtu_updated = gatt_mtu_updated,};

static struct bt_conn_cb conn_cb = {
    .connected = conn_connected,
    .disconnected = conn_disconnected,
    .le_param_req = conn_le_param_req,
    .le_param_updated = conn_le_param_updated,
    .le_phy_updated = conn_le_phy_updated,
    .le_data_len_updated = conn_le_data_len_updated,
};

static struct bt_le_scan_cb scan_cb = {
    .recv = scan_result,
    .timeout = scan_timeout,
};

void gatt_discovery_callback(struct GATTDevice *device, int status)
{
    if (status == DISCOVERY_SUCCESS)
    {
        printk("GATT discovery completed successfully!\n");
        // 在这里处理发现的服务、特征和描述符信息
        print_device_gatt_structure(device);
    }
    else
    {
        printk("GATT discovery failed.\n");
    }
}

// Start the overall discovery process
void start_discovery(struct bt_conn *conn)
{
    printk("Starting service discovery...\n");
    // discover_services(conn);
    gatt_discover(conn, gatt_discovery_callback);
}

static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
                            struct bt_gatt_exchange_params *params)
{
    printk("MTU exchange %u %s (%u)\n", bt_conn_index(conn),
           err == 0U ? "successful" : "failed", bt_gatt_get_mtu(conn));

    start_discovery(default_conn);
}

static int mtu_exchange(struct bt_conn *conn)
{
    uint8_t conn_index;
    int err;

    conn_index = bt_conn_index(conn);

    printk("MTU (%u): %u\n", conn_index, bt_gatt_get_mtu(conn));

    mtu_exchange_params[conn_index].func = mtu_exchange_cb;

    err = bt_gatt_exchange_mtu(conn, &mtu_exchange_params[conn_index]);
    if (err)
    {
        printk("MTU exchange failed (err %d)", err);
    }
    else
    {
        printk("Exchange pending...");
    }

    return err;
}

static void gatt_mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx)
{
    printk("Updated MTU: TX: %d RX: %d bytes\n", tx, rx);
}

static bool conn_le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
{
    printk("Connection parameters update request received.\n");
    printk("Minimum interval: %d, Maximum interval: %d\n",
           param->interval_min, param->interval_max);
    printk("Latency: %d, Timeout: %d\n", param->latency, param->timeout);

    return true;
}

static void conn_le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency,
                                  uint16_t timeout)
{
    printk("Connection parameter updated\n"
           "Connection interval: 1.25 * %u ms, latency: %u, timeout: 10 * %u ms\n",
           interval, latency, timeout);

    // start_discovery(default_conn);
}

static void conn_le_phy_updated(struct bt_conn *conn, struct bt_conn_le_phy_info *param)
{
    printk("PHY updated, TX: %u RX: %u\n", param->tx_phy, param->rx_phy);
}

static void conn_le_data_len_updated(struct bt_conn *conn,
                                     struct bt_conn_le_data_len_info *info)
{
    char addr[BT_ADDR_LE_STR_LEN];

    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

    printk("Data length updated: %s max tx %u (%u us) max rx %u (%u us)\n",
           addr, info->tx_max_len, info->tx_max_time, info->rx_max_len,
           info->rx_max_time);
}

static void conn_connected(struct bt_conn *conn, uint8_t err)
{
    char addr[BT_ADDR_LE_STR_LEN];

    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

    if (err)
    {
        printk("Failed to connect to %s (%u)\n", addr, err);

        bt_conn_unref(default_conn);
        default_conn = NULL;

        start_scan();
        return;
    }

    printk("Connected: %s\n", addr);

    (void)mtu_exchange(conn);

    if (conn == default_conn)
    {
        // start_discovery(conn);
    }
}

static void conn_disconnected(struct bt_conn *conn, uint8_t reason)
{
    struct bt_conn_info conn_info;
    char addr[BT_ADDR_LE_STR_LEN];
    int err;

    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

    err = bt_conn_get_info(conn, &conn_info);
    if (err)
    {
        printk("Failed to get connection info (%d).\n", err);
        return;
    }

    printk("%s: %s role %u (reason %u)\n", __func__, addr, conn_info.role,
           reason);

    default_conn = NULL;

    bt_conn_unref(conn);

    start_scan();
}

static void scan_result(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf)
{
    char dev[BT_ADDR_LE_STR_LEN];
    int err;

    bt_addr_le_to_str(info->addr, dev, sizeof(dev));
    printk("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i\n",
           dev, info->adv_type, buf->len, info->rssi);

    if (memcmp(target_addr, info->addr->a.val, 6) == 0)
    {
        printk("Found target device.\n");

        err = bt_le_scan_stop();
        if (err)
        {
            printk("%s: Stop LE scan failed (err %d)\n", __func__, err);
            return;
        }

        printk("Stop LE scan success.\n");

        err = bt_conn_le_create(info->addr, BT_CONN_LE_CREATE_CONN,
                                BT_LE_CONN_PARAM_DEFAULT, &default_conn);
        if (err)
        {
            printk("%s: Create conn failed (err %d)\n", __func__, err);
            start_scan();
        }
    }
}

static void scan_timeout(void)
{
    printk("scan timeout.\n");
}

static void start_scan(void)
{
    int err;
    struct bt_le_scan_param scan_param = {
        .type = BT_LE_SCAN_TYPE_ACTIVE,
        .options = BT_LE_SCAN_OPT_NONE,
        .interval = BT_GAP_SCAN_FAST_INTERVAL_MIN,
        .window = BT_GAP_SCAN_FAST_WINDOW,
    };

    err = bt_le_scan_start(&scan_param, NULL);
    if (err)
    {
        printk("%s: Scanning failed to start (err %d)\n", __func__, err);
        return;
    }

    printk("%s: Scanning successfully started\n", __func__);
}

int gw_ble_init(void)
{
    int err;

    err = bt_enable(NULL);
    if (err)
    {
        printk("Bluetooth init failed (err %d)\n", err);
        return 0U;
    }
    printk("Bluetooth initialized\n");

    bt_le_scan_cb_register(&scan_cb);
    bt_conn_cb_register(&conn_cb);
    bt_gatt_cb_register(&gatt_cb);

    start_scan();

    return 0;
}
